﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DiagrammInternalStructure;

namespace TestConsole
{
    class Program
    {
        static List<ClassElement> m_classes = new List<ClassElement>();
        static Dictionary<string, Action> m_commands = new Dictionary<string, Action>();
        static ClassElement m_selectedClass = null;

        static void Main(string[] args)
        {
            ClassElement.CreateBasicTypes();
            m_classes.Add(ClassElement.Object);
            m_classes.Add(ClassElement.Void);
            m_classes.Add(ClassElement.String);
            m_classes.Add(ClassElement.Int);
            m_classes.Add(ClassElement.Float);
            m_classes.Add(ClassElement.Double);
            m_classes.Add(ClassElement.Char);
            m_classes.Add(ClassElement.Bool);
            
            bool isEnd = false;

            m_commands.Add("add class", AddClass);
            m_commands.Add("clear", delegate
            {
                Console.Clear();
                m_selectedClass = null;
            });
            m_commands.Add("show", Show);
            m_commands.Add("select class", SelectClass);
            m_commands.Add("add parameter", AddParameter);
            m_commands.Add("exit", () => isEnd = true);

            while (!isEnd)
            {
                string command = Console.ReadLine();
                if (m_commands.ContainsKey(command) && m_commands[command] != null)
                {
                    m_commands[command]();
                }
            }            
        }

        private static void AddClass()
        {
            Console.Clear();
            Console.Write("Name -> ");
            string strName = Console.ReadLine();
            Console.Write("Base -> ");
            string strBase = Console.ReadLine();
            ClassElement baseElement = null;
            foreach (ClassElement ce in m_classes)
            {
                if (ce.Name == strBase)
                {
                    baseElement = ce;
                    break;
                }
            }
            m_classes.Add(new ClassElement(strName, ProtectionType.PublicType, baseElement ?? ClassElement.Object));
            Console.Clear();
        }

        private static void Show()
        {
            Console.Clear();
            if (m_selectedClass == null)
            {
                ClassNotSelectedShow();
            }
            else
            {
                ClassSelectedShow();
            }
        }

        private static void ClassNotSelectedShow()
        {
            string result = string.Empty;

            int DIT = 0;
            foreach (ClassElement ce in m_classes)
            {
                int localDIT = 0;
                string localResult = string.Empty;
                ClassElement copy = ce;
                while (copy.Base != null)
                {
                    if (localResult != string.Empty)
                    {
                        localResult = copy.Name + " <- " + localResult;
                    }
                    else
                    {
                        localResult = copy.Name;
                    }
                    ++localDIT;
                    copy = copy.Base;
                }
                DIT = localDIT > DIT ? localDIT : DIT;
                if (localResult != string.Empty)
                {
                    result += "object <- " + localResult + "\n";
                }
            }
            Console.WriteLine("DIT = " + DIT);
            Console.WriteLine(result);
        }
        private static void ClassSelectedShow()
        {
            switch (m_selectedClass.Protection)
            {
                case ProtectionType.PrivateType:                    
                        Console.Write("- ");
                        break;                    
                case ProtectionType.ProtectedType:
                        Console.Write("# ");
                        break;
                case ProtectionType.PublicType:
                        Console.Write("+ ");
                        break;
            }
            Console.WriteLine(m_selectedClass.Name + (m_selectedClass.Base != null? " : " + m_selectedClass.Base.Name: ""));
            Console.WriteLine(m_selectedClass.IsFinal ? "Final" : "Not Final");

            ParameterField currentParam = null;
            for (uint i = 0; i < m_selectedClass.ParametersCount; ++i)
            {
                currentParam = m_selectedClass.GetParameterByIndex(i);
                Console.WriteLine(currentParam.ToString());
            }
        }
        private static void SelectClass()
        {
            Console.Clear();
            m_selectedClass = null;
            Console.Write("Name ->");
            string name = Console.ReadLine();
            foreach (ClassElement ce in m_classes)
            {
                if (ce.Name == name)
                {
                    m_selectedClass = ce;
                    break;
                }
            }
            if (m_selectedClass == null)
            {
                Console.WriteLine("Class " + name + " not found");
            }
            else
            {
                Console.WriteLine("Class " + name + " selected");
            }
        }

        private static void AddParameter()
        {
            Console.Clear();
            if (m_selectedClass != null)
            {
                string name = string.Empty;
                while (name == string.Empty)
                {
                    Console.Write("Parameter Name ->");
                    name = Console.ReadLine();
                }

                string typeName = string.Empty;
                while (typeName == string.Empty)
                {
                    Console.Write("Type ->");
                    typeName = Console.ReadLine();

                    if (Find(typeName) == null)
                    {
                        Console.WriteLine("Type called " + typeName + " not found");
                        typeName = string.Empty;
                    }
                }

                string protection = string.Empty;
                ProtectionType prot = ProtectionType.PrivateType;
                while (protection == string.Empty)
                {
                    Console.WriteLine("Protection type:\n '+' - public\n '-' - private\n '#' - protected");
                    protection = Console.ReadLine();
                    switch (protection)
                    { 
                        case "+":
                            prot = ProtectionType.PublicType;
                            break;
                        case "-":
                            break;
                        case "#": 
                            prot = ProtectionType.ProtectedType;
                            break;
                        default:
                            Console.WriteLine("Wrong input!");
                            protection = string.Empty;
                            break;
                    }
                }
                ParameterField param = new ParameterField(m_selectedClass, prot, name, Find(typeName));
                if (m_selectedClass.AddParameter(param))
                {
                    Console.Clear();
                }
                else
                {
                    Console.WriteLine("Wrong parameter");
                }
            }
            else
            {
                Console.WriteLine("Class are not selected");
            }
        }

        private static ClassElement Find(string name)
        {
            foreach (ClassElement ce in m_classes)
            {
                if (ce.Name == name)
                {
                    return ce;
                }
            }
            return null;
        }
    }
}
